﻿namespace PhotoAlbum.Web.Services
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Data;
    using System.Linq;
    using System.ServiceModel.DomainServices.EntityFramework;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using PhotoAlbum.Web;

    [EnableClientAccess()]
    public class MemberService : PhotoAlbumService
    {
        [Query(HasSideEffects = false, ResultLimit = 20, IsDefault = true)]
        public IQueryable<PhotoAlbumUser> GetUsers()
        {
            return this.ObjectContext.PhotoAlbumUsers.OrderBy(u => u.UserName);
        }

        [RequiresAuthentication]
        [Query(HasSideEffects = false, ResultLimit = 20)]
        public IQueryable<PhotoAlbumUser> GetFriends()
        {
            return this.PhotoUser.Friends.CreateSourceQuery().OrderBy(u => u.UserName);
        }

        [RequiresAuthentication]
        [Query(HasSideEffects = false, ResultLimit = 20)]
        public IQueryable<PhotoAlbumUser> GetCommonFriends(int otherUserId)
        {
            var user = this.ObjectContext.PhotoAlbumUsers.Include("Friends").FirstOrDefault(u => u.Id == otherUserId);
            if (user == null)
            {
                throw new Exception("User cannot be found.");
            }
            return this.PhotoUser.Friends.CreateSourceQuery().Intersect(user.Friends.CreateSourceQuery());
        }

        [RequiresAuthentication]
        [Query(IsDefault = true, HasSideEffects = false)]
        public IQueryable<FriendRequest> GetFriendRequests()
        {
            return this.PhotoUser
                            .FriendRequests
                            .CreateSourceQuery()
                            .Include("Initiator")
                            .OrderByDescending(fr => fr.DateCreated);
        }

        [RequiresAuthentication]
        [Invoke(HasSideEffects = true)]
        public void RejectFriendRequiestId(int requestId)
        {
            this.PhotoUser.FriendRequests.Load();
            var request = this.PhotoUser.FriendRequests.FirstOrDefault(fr => fr.Id == requestId);
            if (request == null)
            {
                throw new Exception("Friend requets can only be accepted or rejected by the target of the request.");
            }
            ObjectContext.FriendRequests.DeleteObject(request);

            this.ObjectContext.SaveChanges();
        }

        [RequiresAuthentication]
        [Invoke(HasSideEffects = true)]
        public void AcceptFriendRequiestId(int requestId)
        {
            this.PhotoUser.FriendRequests.Load();
            var request = this.PhotoUser.FriendRequests.FirstOrDefault(fr => fr.Id == requestId);
            if (request == null)
            {
                throw new Exception("Friend requets can only be accepted or rejected by the target of the request.");
            }
            request.InitiatorReference.Load();
            var initiator = request.Initiator;
            
            ObjectContext.FriendRequests.DeleteObject(request);

            PhotoUser.Friends.Add(initiator);
            initiator.Friends.Add(PhotoUser);

            this.ObjectContext.SaveChanges();
        }

        [RequiresAuthentication]
        [Invoke(HasSideEffects = true)]
        public void SendFriendRequest([Required] string username)
        {
            var usernameLowcase = username.ToLowerInvariant();
            var targetUser = this.ObjectContext.PhotoAlbumUsers.FirstOrDefault(u => u.UserName.ToLower() == usernameLowcase);

            if (targetUser == null)
            {
                throw new Exception("Traget user not found.");
            }

            var request = new FriendRequest()
            {
                DateCreated = DateTime.UtcNow,
                InitiatorId = this.PhotoUser.Id,
                TargetId = targetUser.Id,
            };

            ObjectContext.AddToFriendRequests(request);
            ObjectContext.SaveChanges();
        }
    }
}


